﻿using CSRedis;
using Lemon.Blog.Blog.Dtos;
using Lemon.Blog.Users;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Unicode;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;

namespace Lemon.Blog.Blog
{
    public class BlogService:BlogAppService, IBlogService
    {
        private readonly IFreeSql _freeSql;
        private readonly CSRedisClient _redis;

        public BlogService(IFreeSql freeSql,
            CSRedisClient redis)
        {
            this._freeSql = freeSql;
            this._redis = redis;
        }

        /// <summary>
        /// 发布博客
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [Authorize]
        public async Task<long> CreateBlog(BlogDto dto)
        {
            try
            {
                //if (CurrentUser.Id == Guid.Empty)
                //    throw new UserFriendlyException("请登录");
                Blog blog = ObjectMapper.Map<BlogDto, Blog>(dto);
                blog.CreateTime = DateTime.Now;
                blog.UserId = (Guid)CurrentUser.Id;
                blog.LikeCount = 0;
                blog.ReadCount = 0;
                return await _freeSql.Insert(blog).ExecuteIdentityAsync();
                
            }
            catch(Exception ex)
            {
                throw new UserFriendlyException(ex.Message);
            }
        }

        /// <summary>
        /// 删除博客
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Authorize]
        public async Task DeleteBlog(int id)
        {
            Blog blog = await _freeSql.Select<Blog>()
                .Where(t => t.Id == id).ToOneAsync();
            if (!CurrentUser.Roles.Contains("admin") && blog.UserId != CurrentUser.Id)
                throw new UserFriendlyException("无权限删除");
            else
                await _freeSql.Delete<Blog>().Where(t => t.Id == id).ExecuteAffrowsAsync();
        }

        /// <summary>
        /// 博客详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<BlogResultDto> GetBlogDetails(int id)
        {
            var query = await _freeSql.Select<Blog, AppUser>()
                .LeftJoin(t => t.t1.UserId == t.t2.Id)
                .Where(t => t.t1.Id == id)
                .ToOneAsync(t => new { t.t1, t.t2 });
            BlogResultDto result = ObjectMapper.Map<Blog, BlogResultDto>(query.t1);
            result.UserName = query.t2.UserName;
            result.HeadPhoto = query.t2.HeadPhoto;
            result.ReplyList = await ReplyList(id);
            return result;
        }

        /// <summary>
        /// 根据用户分页获取博客列表
        /// </summary>
        /// <param name="UserId"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<BlogResultDto>> GetBlogList(GetBlogListDto dto)
        {
            Guid UserId = new Guid();
            if(!string.IsNullOrEmpty(dto.UserName))
            {
                UserId = _freeSql.Select<AppUser>()
                    .Where(t => t.UserName == dto.UserName)
                    .ToOne(t => t.Id);
            }
            var query = await _freeSql.Select<Blog, AppUser>()
                .LeftJoin(t => t.t1.UserId == t.t2.Id)
                .WhereIf(!string.IsNullOrEmpty(dto.UserName), t => t.t1.UserId == UserId)
                .OrderByDescending(t => t.t1.CreateTime)
                .Count(out var total)
                .Page((dto.SkipCount / dto.MaxResultCount) + 1, dto.MaxResultCount)
                .ToListAsync(t => new { t.t1, t.t2 });
            var result = new List<BlogResultDto>();
            foreach (var item in query)
            {
                BlogResultDto d = ObjectMapper.Map<Blog, BlogResultDto>(item.t1);
                d.UserName = item.t2.UserName;
                d.Name = item.t2.Name;
                d.HeadPhoto = item.t2.HeadPhoto;
                d.ReplyList = await ReplyList(item.t1.Id);
                result.Add(d);
            }
            return new PagedResultDto<BlogResultDto>() { TotalCount = total, Items = result };
        }

        /// <summary>
        /// 发表回复
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [Authorize]
        public async Task<BlogReplyResultDto> CreateReply(BlogReplyDto dto)
        {
            try
            {
                BlogReply blogReply = ObjectMapper.Map<BlogReplyDto, BlogReply>(dto);
                blogReply.CreateTime = DateTime.Now;
                blogReply.ReplyUserId = (Guid)CurrentUser.Id;
                if (blogReply.Content.StartsWith("回复 @"))
                    blogReply.Content = blogReply.Content[(blogReply.Content.IndexOf(':') + 1)..];
                long id = await _freeSql.Insert(blogReply).ExecuteIdentityAsync();

                
                BlogReplyResultDto result = ObjectMapper.Map<BlogReply, BlogReplyResultDto>(blogReply);
                result.BlogReplyId = (int)id;
                if (blogReply.ReplyToId != null)
                {
                    var query = await _freeSql.Select<BlogReply, AppUser>()
                        .LeftJoin(t => t.t1.ReplyUserId == t.t2.Id)
                        .Where(t => t.t1.Id == blogReply.ReplyToId)
                        .ToOneAsync(t => new { t.t1, t.t2 });;
                    result.ReplyToUserName = query.t2.UserName;
                    result.ReplyToName = query.t2.Name;
                }
                return result;
            }
            catch (Exception ex)
            {
                throw new UserFriendlyException(ex.Message);
            }
        }

        /// <summary>
        /// 删除评论
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Authorize]
        public async Task DeleteReply(int id)
        {
            BlogReply blogReply = await _freeSql.Select<BlogReply>()
                .Where(t => t.Id == id).ToOneAsync();
            if (!CurrentUser.Roles.Contains("admin") && blogReply.ReplyUserId != CurrentUser.Id && blogReply.Blog.UserId != CurrentUser.Id)
                throw new UserFriendlyException("无权限删除");
            else
                await _freeSql.Delete<BlogReply>().Where(t=>t.Id == id).ExecuteAffrowsAsync();
        }

        /// <summary>
        /// 回复列表
        /// </summary>
        /// <param name="blogId"></param>
        /// <returns></returns>
        public async Task<List<BlogReplyResultDto>> ReplyList(int blogId)
        {
            var query = await _freeSql.Select<BlogReply, AppUser>()
                .LeftJoin(t => t.t1.ReplyUserId == t.t2.Id)
                .Where(t => t.t1.BlogId == blogId)
                .ToListAsync(t => new { t.t1, t.t2 });
            var result = new List<BlogReplyResultDto>();
            foreach (var item in query)
            {
                BlogReplyResultDto dto = ObjectMapper.Map<BlogReply, BlogReplyResultDto>(item.t1);
                dto.UserName = item.t2.UserName;
                dto.HeadPhoto = item.t2.HeadPhoto;
                dto.Name = item.t2.Name;
                if(item.t1.ReplyToId != null)
                {
                    var replyTo = query.Find(t => t.t1.Id == item.t1.ReplyToId);
                    if (replyTo != null)
                    {
                        dto.ReplyToUserName = replyTo.t2.UserName;
                        dto.ReplyToName = replyTo.t2.Name;
                    }
                    else
                    {
                        dto.ReplyToUserName = "评论已被删除";
                        dto.ReplyToName = "评论已被删除";
                    }
                }
                result.Add(dto);
            }
            return result;
        }

        /// <summary>
        /// 点赞
        /// </summary>
        /// <param name="blogId"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<long> GiveLike(int blogId)
        {
            if(!await _redis.HExistsAsync("BlogLike", blogId.ToString()))
            {
                int likeCount = await _freeSql.Select<Blog>()
                    .Where(t => t.Id == blogId)
                    .ToOneAsync(t => t.LikeCount);
                await _redis.HSetAsync("BlogLike", blogId.ToString(), likeCount);
            }
            return await _redis.HIncrByAsync("BlogLike", blogId.ToString());
        }
    }
}
